<template>
  <Modal v-model="show" className="img-viewer" fullScreen transparent>
    <div class="wrapper" ref="wrapper">
      <!---- CLOSE -->
      <span class="btn-group close btn" @click="hide">
        <i class="h-icon-close"/>
      </span>
      <!--ARROW-->
      <template v-if="!isSingle">
         <span class="btn-group left btn" @click="prev">
        <i class="h-icon-left"/>
      </span>
        <span class="btn-group right btn" @click="next">
        <i class="h-icon-right"/>
      </span>
      </template>
      <!-- ACTIONS -->
      <div class="btn-group actions">
      <span @click="handleActions('zoomOut')">
        <svg t="1659360703293" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
             p-id="4808" width="128" height="128"><path
            d="M818.214912 772.134912l128 128c6.144 6.827008 9.216 14.507008 9.216 23.04 0 8.534016-3.241984 16.043008-9.728 22.528-6.484992 6.486016-13.993984 9.728-22.528 9.728-8.532992 0-16.212992-3.072-23.04-9.216l-128-128c-90.793984 74.411008-191.488 108.374016-302.08 101.888-110.592-6.484992-206.505984-51.712-287.744-135.68-77.824-88.064-115.712-187.392-113.664-297.984s43.691008-208.212992 124.928-292.864c84.651008-81.236992 182.272-122.88 292.864-124.928s209.92 35.84 297.984 113.664c83.968 81.238016 129.195008 177.152 135.68 287.744 6.486016 110.592-27.476992 211.286016-101.888 302.08z m-323.584 82.944c102.4-2.729984 187.392-37.888 254.976-105.472s102.742016-152.576 105.472-254.976c-2.729984-102.4-37.888-187.392-105.472-254.976s-152.576-102.740992-254.976-105.472c-102.4 2.731008-187.392 37.888-254.976 105.472s-102.740992 152.576-105.472 254.976c2.731008 102.4 37.888 187.392 105.472 254.976s152.576 102.742016 254.976 105.472z m-131.072-393.216h262.144c9.558016 0 17.408 3.072 23.552 9.216s9.216 13.995008 9.216 23.552c0 9.558016-3.072 17.408-9.216 23.552s-13.993984 9.216-23.552 9.216h-262.144c-9.556992 0-17.408-3.072-23.552-9.216s-9.216-13.993984-9.216-23.552c0-9.556992 3.072-17.408 9.216-23.552s13.995008-9.216 23.552-9.216z"
            p-id="4809" fill="#ffffff"></path></svg>
      </span>
        <span @click="handleActions('zoomIn')">
        <svg t="1659360721802" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
             p-id="5010" width="128" height="128"><path
            d="M818.214912 772.134912l128 128c6.144 6.827008 9.216 14.507008 9.216 23.04 0 8.534016-3.241984 16.043008-9.728 22.528-6.484992 6.486016-13.993984 9.728-22.528 9.728-8.532992 0-16.212992-3.072-23.04-9.216l-128-128c-90.793984 74.411008-191.488 108.374016-302.08 101.888-110.592-6.484992-206.505984-51.712-287.744-135.68-77.824-88.064-115.712-187.392-113.664-297.984s43.691008-208.212992 124.928-292.864c84.651008-81.236992 182.272-122.88 292.864-124.928s209.92 35.84 297.984 113.664c83.968 81.238016 129.195008 177.152 135.68 287.744 6.486016 110.592-27.476992 211.286016-101.888 302.08z m-323.584 82.944c102.4-2.729984 187.392-37.888 254.976-105.472s102.742016-152.576 105.472-254.976c-2.729984-102.4-37.888-187.392-105.472-254.976s-152.576-102.740992-254.976-105.472c-102.4 2.731008-187.392 37.888-254.976 105.472s-102.740992 152.576-105.472 254.976c2.731008 102.4 37.888 187.392 105.472 254.976s152.576 102.742016 254.976 105.472z m-32.768-393.216v-98.304c0-9.556992 3.072-17.408 9.216-23.552s13.995008-9.216 23.552-9.216c9.558016 0 17.408 3.072 23.552 9.216s9.216 13.995008 9.216 23.552v98.304h98.304c9.558016 0 17.408 3.072 23.552 9.216s9.216 13.995008 9.216 23.552c0 9.558016-3.072 17.408-9.216 23.552s-13.993984 9.216-23.552 9.216h-98.304v98.304c0 9.558016-3.072 17.408-9.216 23.552s-13.993984 9.216-23.552 9.216c-9.556992 0-17.408-3.072-23.552-9.216s-9.216-13.993984-9.216-23.552v-98.304h-98.304c-9.556992 0-17.408-3.072-23.552-9.216s-9.216-13.993984-9.216-23.552c0-9.556992 3.072-17.408 9.216-23.552s13.995008-9.216 23.552-9.216h98.304z"
            p-id="5011" fill="#ffffff"></path></svg>
      </span>
        <i style="text-align: justify"></i>
        <span @click="toggleMode">
        <svg v-if="mode.name=='contain'" t="1659360554764" class="icon" viewBox="0 0 1024 1024" version="1.1"
             xmlns="http://www.w3.org/2000/svg" p-id="4384" width="128" height="128"><path
            d="M151.552 86.016h196.608c9.556992 0.683008 17.408 4.096 23.552 10.24s9.216 13.824 9.216 23.04-3.072 16.896-9.216 23.04-13.995008 9.216-23.552 9.216H151.552v196.608c0 9.556992-3.072 17.408-9.216 23.552s-13.995008 9.216-23.552 9.216-17.408-3.072-23.552-9.216-9.216-13.995008-9.216-23.552V86.016h65.536z m0 851.968H86.016V675.84c0-9.556992 3.072-17.408 9.216-23.552s13.995008-9.216 23.552-9.216 17.408 3.072 23.552 9.216 9.216 13.995008 9.216 23.552v196.608h196.608c9.556992 0 17.408 3.072 23.552 9.216s9.216 13.824 9.216 23.04-3.072 16.896-9.216 23.04-13.995008 9.556992-23.552 10.24H151.552zM872.448 86.016h65.536v262.144c0 9.556992-3.072 17.408-9.216 23.552s-13.995008 9.216-23.552 9.216-17.408-3.072-23.552-9.216-9.216-13.995008-9.216-23.552V151.552H675.84c-9.556992 0-17.408-3.072-23.552-9.216s-9.216-13.824-9.216-23.04 3.072-16.896 9.216-23.04 13.995008-9.556992 23.552-10.24h196.608z m0 851.968H675.84c-9.556992-0.683008-17.408-4.096-23.552-10.24s-9.216-13.824-9.216-23.04 3.072-16.896 9.216-23.04 13.995008-9.216 23.552-9.216h196.608V675.84c0-9.556992 3.072-17.408 9.216-23.552s13.995008-9.216 23.552-9.216 17.408 3.072 23.552 9.216 9.216 13.995008 9.216 23.552v262.144h-65.536z"
            p-id="4385" fill="#ffffff"></path></svg>
        <svg v-else t="1659360662748" class="icon" viewBox="0 0 1024 1024" version="1.1"
             xmlns="http://www.w3.org/2000/svg" p-id="4594" width="128" height="128"><path
            d="M820.224 204.288c17.748992 0 32.427008 5.803008 44.032 17.408 11.604992 11.604992 17.408 26.283008 17.408 44.032v493.568c0 17.067008-5.972992 31.572992-17.92 43.52-11.947008 11.947008-26.452992 17.92-43.52 17.92H203.776c-17.067008 0-31.572992-5.972992-43.52-17.92-11.947008-11.947008-17.92-26.452992-17.92-43.52v-493.568c0-17.748992 5.803008-32.427008 17.408-44.032 11.604992-11.604992 26.283008-17.408 44.032-17.408h616.448z m0-62.464H203.776c-16.384 0.683008-32.084992 4.096-47.104 10.24-15.019008 6.144-28.331008 15.019008-39.936 26.624-11.604992 11.604992-20.651008 24.916992-27.136 39.936-6.484992 15.019008-9.728 30.72-9.728 47.104v493.568c0 16.384 3.243008 32.084992 9.728 47.104 6.484992 15.019008 15.531008 28.331008 27.136 39.936 11.604992 11.604992 24.916992 20.48 39.936 26.624 15.019008 6.144 30.72 9.216 47.104 9.216h616.448c16.384 0 32.084992-3.072 47.104-9.216 15.019008-6.144 28.331008-15.019008 39.936-26.624 11.604992-11.604992 20.651008-24.916992 27.136-39.936 6.484992-15.019008 9.728-30.72 9.728-47.104v-493.568c0-16.384-3.243008-32.084992-9.728-47.104-6.484992-15.019008-15.531008-28.331008-27.136-39.936-11.604992-11.604992-24.916992-20.48-39.936-26.624-15.019008-6.144-30.72-9.556992-47.104-10.24z m-122.88 185.344c-8.875008 0-16.212992 3.072-22.016 9.216s-8.704 13.312-8.704 21.504v308.224c0 8.875008 2.900992 16.212992 8.704 22.016s13.140992 8.704 22.016 8.704 16.212992-2.900992 22.016-8.704 8.704-13.140992 8.704-22.016v-308.224c0-8.875008-2.900992-16.212992-8.704-22.016s-13.140992-8.704-22.016-8.704z m-370.688 0c-8.192 0-15.36 3.072-21.504 9.216s-9.216 13.312-9.216 21.504v308.224c0 8.875008 2.900992 16.212992 8.704 22.016s13.140992 8.704 22.016 8.704 16.212992-2.900992 22.016-8.704 8.704-13.140992 8.704-22.016v-308.224c0-8.192-2.900992-15.36-8.704-21.504s-13.140992-9.216-22.016-9.216z m185.344 61.44c-8.875008 0.683008-16.212992 3.924992-22.016 9.728s-8.704 13.140992-8.704 22.016v30.72c0 8.192 2.900992 15.188992 8.704 20.992s13.140992 8.704 22.016 8.704 16.212992-2.900992 22.016-8.704 8.704-12.8 8.704-20.992v-30.72c0-8.875008-3.072-16.212992-9.216-22.016s-13.312-9.044992-21.504-9.728z m0 154.624c-8.875008 0-16.212992 2.900992-22.016 8.704s-8.704 13.140992-8.704 22.016v30.72c0 8.875008 2.900992 16.212992 8.704 22.016s13.140992 8.704 22.016 8.704 16.212992-2.900992 22.016-8.704 8.704-13.140992 8.704-22.016v-30.72c0-8.192-3.072-15.36-9.216-21.504s-13.312-9.216-21.504-9.216z"
            p-id="4595" fill="#ffffff"></path></svg>
      </span>
        <i style="text-align: justify"></i>
        <span @click="handleActions('anticlockwise')">
        <svg t="1659360492351" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
             p-id="3980" width="128" height="128"><path
            d="M270.336 290.75968h95.232c9.556992 0 17.408 3.072 23.552 9.216s9.216 13.824 9.216 23.04-3.072 16.896-9.216 23.04-13.995008 9.556992-23.552 10.24H212.992c-9.556992-0.683008-17.408-4.096-23.552-10.24s-9.216-13.652992-9.216-22.528v-152.576c0-9.556992 3.072-17.408 9.216-23.552s13.995008-9.216 23.552-9.216 17.408 3.072 23.552 9.216 9.216 13.995008 9.216 23.552v51.2c58.708992-52.564992 125.780992-85.163008 201.216-97.792 75.435008-12.628992 149.675008-3.584 222.72 27.136 72.363008 32.768 129.536 81.236992 171.52 145.408s63.316992 135.851008 64 215.04c-2.731008 111.275008-41.131008 203.947008-115.2 278.016S623.275008 902.428672 512 905.15968c-111.275008-2.731008-203.947008-41.131008-278.016-115.2S121.515008 623.218688 118.784 511.94368h65.536c2.048 92.843008 33.963008 170.155008 95.744 231.936s139.092992 93.696 231.936 95.744c92.843008-2.048 169.984-33.963008 231.424-95.744s93.524992-139.092992 96.256-231.936c-0.683008-68.948992-19.796992-130.56-57.344-184.832s-88.064-94.379008-151.552-120.32c-64.171008-23.892992-128.512-28.500992-193.024-13.824-64.512 14.676992-120.32 47.275008-167.424 97.792z"
            p-id="3981" fill="#ffffff"></path></svg>
      </span>
        <span @click="handleActions('clockwise')">
        <svg t="1659360526591" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"
             p-id="4230" width="128" height="128"><path
            d="M778.24 222.108672v-51.2c0-9.556992 3.072-17.408 9.216-23.552s13.824-9.216 23.04-9.216 16.896 3.072 23.04 9.216 9.556992 13.995008 10.24 23.552v152.576c-0.683008 8.875008-4.096 16.384-10.24 22.528s-13.652992 9.556992-22.528 10.24H658.432c-9.556992-0.683008-17.408-4.096-23.552-10.24s-9.216-13.824-9.216-23.04 3.072-16.896 9.216-23.04 13.995008-9.216 23.552-9.216h95.232c-53.248-55.979008-115.883008-89.940992-187.904-101.888-72.020992-11.947008-141.824-0.171008-209.408 35.328-66.900992 36.864-115.028992 88.747008-144.384 155.648s-35.156992 137.899008-17.408 212.992c19.796992 73.728 58.539008 132.948992 116.224 177.664s124.756992 67.755008 201.216 69.12c92.843008-2.048 169.984-33.963008 231.424-95.744s93.524992-139.092992 96.256-231.936h65.536c-2.731008 111.275008-41.131008 203.947008-115.2 278.016S623.275008 902.385664 512 905.116672c-111.275008-2.731008-203.947008-41.131008-278.016-115.2S121.515008 623.17568 118.784 511.900672c0.683008-79.188992 21.844992-150.868992 63.488-215.04s98.644992-112.299008 171.008-144.384c73.044992-31.403008 147.284992-40.788992 222.72-28.16 75.435008 12.628992 142.848 45.227008 202.24 97.792z"
            p-id="4231"></path></svg>
      </span>
      </div>
      <!--canvas-->
      <div class="canvas">
        <img
            v-for="(url, i) in urlList"
            v-show="i === index"
            :ref="(el) => (imgRefs[i] = el)"
            :key="url"
            :src="url"
            :style="imgStyle"
            class="img"
            @load="handleImgLoad"
            @error="handleImgError"
            @mousedown="handleMouseDown"
        />
      </div>
    </div>
  </Modal>
</template>

<script setup>
import {
  computed,
  effectScope,
  markRaw,
  nextTick,
  onMounted,
  ref,
  shallowRef,
  watch,
  isRef, unref, onUnmounted, onDeactivated, onActivated
} from 'vue'
import {util} from 'framework'
const EVENT_CODE = {
  tab: 'Tab',
  enter: 'Enter',
  space: 'Space',
  left: 'ArrowLeft', // 37
  up: 'ArrowUp', // 38
  right: 'ArrowRight', // 39
  down: 'ArrowDown', // 40
  esc: 'Escape',
  delete: 'Delete',
  backspace: 'Backspace',
  numpadEnter: 'NumpadEnter',
  pageUp: 'PageUp',
  pageDown: 'PageDown',
  home: 'Home',
  end: 'End',
}

const modes = {
  CONTAIN: {
    name: 'contain',
    icon: 'icon-expand',
  },
  ORIGINAL: {
    name: 'original',
    icon: 'icon-contract',
  },
}, show = ref(true)
const mousewheelEventName = 'mousewheel'
const props = defineProps({
  urlList: {
    type: Array,
    default: [],
  },
  initialIndex: {
    type: Number,
    default: 0
  },
  modelValue: {
    type: Boolean,
    default: false
  }
})
const emit = defineEmits(['close', 'switch', 'update:modelValue'])

const wrapper = ref()
const imgRefs = ref([])
const scopeEventListener = effectScope()
const loading = ref(true)
const index = ref(props.initialIndex)
const mode = shallowRef(modes.CONTAIN)
const transform = ref({
  scale: 1,
  deg: 0,
  offsetX: 0,
  offsetY: 0,
  enableTransition: false,
})

const isNumber = (v) => isFinite(Number(v))

const isSingle = computed(() => {
  const {urlList} = props
  return urlList.length <= 1
})
const isFirst = computed(() => {
  return index.value === 0
})
const isLast = computed(() => {
  return index.value === props.urlList.length - 1
})
const currentImg = computed(() => {
  return props.urlList[index.value]
})
const imgStyle = computed(() => {
  const {scale, deg, offsetX, offsetY, enableTransition} = transform.value
  let translateX = offsetX / scale
  let translateY = offsetY / scale
  switch (deg % 360) {
    case 90:
    case -270:
      ;[translateX, translateY] = [translateY, -translateX]
      break
    case 180:
    case -180:
      ;[translateX, translateY] = [-translateX, -translateY]
      break
    case 270:
    case -90:
      ;[translateX, translateY] = [-translateY, translateX]
      break
  }
  const style = {
    transform: `scale(${scale}) rotate(${deg}deg) translate(${translateX}px, ${translateY}px)`,
    transition: enableTransition ? 'transform .3s' : '',
  }
  if (mode.value.name === modes.CONTAIN.name) {
    style.maxWidth = style.maxHeight = '100%'
  }
  return style
})

function hide() {
  show.value = false
  unregisterEventListener()
  emit('close')
  emit('update:modelValue', false)
}

const throttle=util.throttle
const useEventListener=util.useEventListener
function registerEventListener() {
  const keydownHandler = throttle((e) => {
    switch (e.code) {
        // ESC
      case EVENT_CODE.esc:
         hide()
        break
        // SPACE
      case EVENT_CODE.space:
        toggleMode()
        break
        // LEFT_ARROW
      case EVENT_CODE.left:
        prev()
        break
        // UP_ARROW
      case EVENT_CODE.up:
        handleActions('zoomIn')
        break
        // RIGHT_ARROW
      case EVENT_CODE.right:
        next()
        break
        // DOWN_ARROW
      case EVENT_CODE.down:
        handleActions('zoomOut')
        break
    }
  })
  const mousewheelHandler = throttle((e) => {
        const delta = e.wheelDelta ? e.wheelDelta : -e.detail
        if (delta > 0) {
          handleActions('zoomIn', {
            zoomRate: 1.2,
            enableTransition: false,
          })
        } else {
          handleActions('zoomOut', {
            zoomRate: 1.2,
            enableTransition: false,
          })
        }
      }
  )
  scopeEventListener.run(() => {
    useEventListener(document, 'keydown', keydownHandler)
    useEventListener(document, mousewheelEventName, mousewheelHandler)
  })
}

function unregisterEventListener() {
  scopeEventListener.stop()
}

function handleImgLoad() {
  loading.value = false
}

function handleImgError(e) {
  loading.value = false;
  e.target.alt = "图片加载失败"
}

function handleMouseDown(e) {
  if (loading.value || e.button !== 0 || !wrapper.value) return
  transform.value.enableTransition = false
  const {offsetX, offsetY} = transform.value
  const startX = e.pageX
  const startY = e.pageY
  const dragHandler = throttle((ev) => {
    transform.value = {
      ...transform.value,
      offsetX: offsetX + ev.pageX - startX,
      offsetY: offsetY + ev.pageY - startY,
    }
  })
  const removeMousemove = useEventListener(document, 'mousemove', dragHandler)
  useEventListener(document, 'mouseup', () => {
    removeMousemove()
  })
  e.preventDefault()
}

function reset() {
  transform.value = {
    scale: 1,
    deg: 0,
    offsetX: 0,
    offsetY: 0,
    enableTransition: false,
  }
}

function toggleMode() {
  if (loading.value) return
  const modeNames = Object.keys(modes)
  const modeValues = Object.values(modes)
  const currentMode = mode.value.name
  const index = modeValues.findIndex((i) => i.name === currentMode)
  const nextIndex = (index + 1) % modeNames.length
  mode.value = modes[modeNames[nextIndex]]
  reset()
}

function prev() {
  if (isFirst.value && !props.infinite) return
  const len = props.urlList.length
  index.value = (index.value - 1 + len) % len
}

function next() {
  if (isLast.value && !props.infinite) return
  const len = props.urlList.length
  index.value = (index.value + 1) % len
}

function handleActions(action, options = {}) {
  if (loading.value) return
  const {zoomRate, rotateDeg, enableTransition} = {
    zoomRate: 1.4,
    rotateDeg: 90,
    enableTransition: true,
    ...options,
  }
  switch (action) {
    case 'zoomOut':
      if (transform.value.scale > 0.2) {
        transform.value.scale = Number.parseFloat(
            (transform.value.scale / zoomRate).toFixed(3)
        )
      }
      break
    case 'zoomIn':
      if (transform.value.scale < 7) {
        transform.value.scale = Number.parseFloat(
            (transform.value.scale * zoomRate).toFixed(3)
        )
      }
      break
    case 'clockwise':
      transform.value.deg += rotateDeg
      break
    case 'anticlockwise':
      transform.value.deg -= rotateDeg
      break
  }
  transform.value.enableTransition = enableTransition
}

watch(currentImg, () => {
  nextTick(() => {
    const $img = imgRefs.value[0]
    if (!$img?.complete) {
      loading.value = true
    }
  })
})
watch(index, (val) => {
  reset()
  emit('switch', val)
})
onMounted(() => {
  registerEventListener()
  // add tabindex then wrapper can be focusable via Javascript
  // focus wrapper so arrow key can't cause inner scroll behavior underneath
  wrapper.value?.focus?.()
})
</script>
<style scoped>
.btn-group {
  border-radius: 50vh;
  height: 40px;
  font-size: 24px;
  color: #fff;
  background-color: #606266;
  opacity: .8;
  z-index: 1;
}

.btn {
  cursor: pointer;
  justify-content: center;
  align-items: center;
  display: flex;
}

.close {
  top: 40px;
  right: 40px;
  width: 40px;
  position: absolute;
}

.left {
  left: 40px;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  position: absolute;
}

.right {
  right: 40px;
  top: 50%;
  transform: translateY(-50%);
  width: 44px;
  height: 44px;
  position: absolute;
}

.actions {
  position: absolute;
  left: 50%;
  bottom: 30px;
  transform: translateX(-50%);
  width: 282px;
  height: 44px;
  padding: 0 23px;
  background-color: #606266;
  border-color: #fff;
  border-radius: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: .8;
  user-select: none;
  display: flex;
  align-items: center;
  justify-content: space-around;
}

.actions > span {

}

.canvas {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

.wrapper {
  position: absolute;
  padding: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
</style>
<style>
.h-modal.img-viewer .h-notify-body {
  padding: 0;
}

</style>
